interface Callback<T, P> {
  (params?: P): Promise<T>
  clearCache(): void
}

export const networkCache = <T, P>(
  apiCallback: (params?: P) => Promise<T>,
  cacheDuration: number = 10000
): Callback<T, P> => {
  let taskingPromise: Promise<T> = null
  let cache: T | null = null
  let lastCacheTime = 0
  let lastParams: any = null

  const fn = async (params?: any): Promise<T> => {
    const stringParams = JSON.stringify(params)

    if (stringParams !== lastParams) {
      taskingPromise = null
      cache = null
      lastCacheTime = 0
    }
    lastParams = stringParams
    if (taskingPromise) {
      return taskingPromise
    }
    if (cache && Date.now() - lastCacheTime < cacheDuration) {
      return cache
    }
    taskingPromise = apiCallback(params)
    cache = await taskingPromise
    lastCacheTime = Date.now()
    return cache
  }
  fn.clearCache = () => (cache = null) as any
  return fn
}
